﻿/* Copyright (C) 2007-2010 STS Soft

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 of the License.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using STSdb.General.Buffers;
using STSdb.General.Collections;

namespace STSdb.Data
{
    partial class FTable<TKey, TRecord>
    {
        internal interface IRecordCollection : IEnumerable<KeyValuePair<BinaryBuffer, TRecord>>
        {
            bool Remove(BinaryBuffer key);
            bool TryGetValue(BinaryBuffer key, out TRecord record);
            TRecord this[BinaryBuffer key] { get; set; }
            KeyValuePair<BinaryBuffer, TRecord> this[int index] { get; }
            int Search(BinaryBuffer key);
            void Sort();

            int Count { get; }
        }

        internal class DictionaryRecordCollection : IRecordCollection
        {
            private readonly Dictionary<BinaryBuffer, TRecord> Collection;

            public DictionaryRecordCollection(int capacity)
            {
                Collection = new Dictionary<BinaryBuffer, TRecord>(capacity);
            }

            public DictionaryRecordCollection(BinaryBuffer[] keys, IIndexer<TRecord> records)
                :this(keys.Length)
            {
                for (int i = 0; i < keys.Length; i++)
                    Collection.Add(keys[i], records[i]);
            }

            #region IRecordCollection Members

            public bool Remove(BinaryBuffer key)
            {
                return Collection.Remove(key);
            }

            public bool TryGetValue(BinaryBuffer key, out TRecord record)
            {
                return Collection.TryGetValue(key, out record);
            }

            public TRecord this[BinaryBuffer key]
            {
                get
                {
                    return Collection[key];
                }
                set
                {
                    Collection[key] = value;
                }
            }

            public KeyValuePair<BinaryBuffer, TRecord> this[int index]
            {
                get { throw new Exception("Logical error."); }
            }

            public int Search(BinaryBuffer key)
            {
                throw new Exception("Logical error.");
            }

            public void Sort()
            {
                throw new Exception("Logical error.");
            }

            public int Count
            {
                get { return Collection.Count; }
            }

            #endregion

            #region IEnumerable<KeyValuePair<BinaryBuffer,TRecord>> Members

            public IEnumerator<KeyValuePair<BinaryBuffer, TRecord>> GetEnumerator()
            {
                return Collection.GetEnumerator();
            }

            #endregion

            #region IEnumerable Members

            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }

            #endregion
        }

        internal class SortedListRecordCollection : IRecordCollection
        {
            private bool IsSorted = false;
            private readonly List<KeyValuePair<BinaryBuffer, TRecord>> Collection;

            public SortedListRecordCollection(int capacity)
            {
                Collection = new List<KeyValuePair<BinaryBuffer, TRecord>>(capacity);
            }

            public SortedListRecordCollection(IRecordCollection collection)
                : this(collection.Count)
            {
                Collection.AddRange(collection);
            }

            public SortedListRecordCollection(BinaryBuffer[] keys, IIndexer<TRecord> records)
                : this(keys.Length)
            {
                for (int i = 0; i < keys.Length; i++)
                    Collection.Add(new KeyValuePair<BinaryBuffer, TRecord>(keys[i], records[i]));
            }

            #region IRecordCollection Members

            public bool Remove(BinaryBuffer key)
            {
                Sort();

                int idx = Collection.BinarySearch(new KeyValuePair<BinaryBuffer, TRecord>(key, default(TRecord)), KeyComparer.Instance);
                if (idx < 0)
                    return false;

                Collection.RemoveAt(idx);
                return true;
            }

            public bool TryGetValue(BinaryBuffer key, out TRecord record)
            {
                Sort();

                int idx = Collection.BinarySearch(new KeyValuePair<BinaryBuffer, TRecord>(key, default(TRecord)), KeyComparer.Instance);
                if (idx < 0)
                {
                    record = default(TRecord);
                    return false;
                }

                record = Collection[idx].Value;
                return true;
            }

            public TRecord this[BinaryBuffer key]
            {
                get
                {
                    TRecord record;
                    if (!TryGetValue(key, out record))
                        throw new KeyNotFoundException(key.ToString());

                    return record;
                }
                set
                {
                    Sort();

                    KeyValuePair<BinaryBuffer, TRecord> kv = new KeyValuePair<BinaryBuffer, TRecord>(key, value);

                    int idx = Collection.BinarySearch(kv, KeyComparer.Instance);
                    if (idx < 0)
                        Collection.Insert(~idx, kv);
                    else
                        Collection[idx] = kv;
                }
            }

            public KeyValuePair<BinaryBuffer, TRecord> this[int index]
            {
                get { return Collection[index]; }
            }

            public int Count
            {
                get { return Collection.Count; }
            }

            public int Search(BinaryBuffer key)
            {
                Sort();

                return Collection.BinarySearch(new KeyValuePair<BinaryBuffer, TRecord>(key, default(TRecord)), KeyComparer.Instance);
            }

            public void Sort()
            {
                if (!IsSorted)
                    Collection.Sort(KeyComparer.Instance);
            }

            #endregion

            #region IEnumerable<KeyValuePair<BinaryBuffer,TRecord>> Members

            public IEnumerator<KeyValuePair<BinaryBuffer, TRecord>> GetEnumerator()
            {
                return Collection.GetEnumerator();
            }

            #endregion

            #region IEnumerable Members

            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }

            #endregion

            private class KeyComparer : IComparer<KeyValuePair<BinaryBuffer, TRecord>>
            {
                public static readonly KeyComparer Instance = new KeyComparer();

                #region IComparer<KeyValuePair<BinaryBuffer,TRecord>> Members

                public int Compare(KeyValuePair<BinaryBuffer, TRecord> x, KeyValuePair<BinaryBuffer, TRecord> y)
                {
                    return x.Key.Raw.ReverseCompareTo(y.Key.Raw);
                }

                #endregion
            }
        }
    }
}
